// query utils

let _ = require('underscore');
// require('string-format-js');
let format = require('string-format');
let mongoose = require('mongoose');

let queryUtils = module.exports = {};

let ObjectId = mongoose.Types.ObjectId;

// owe and hope fuzzy query fields
queryUtils.oweHopefields = ['no', 'author', 'cellphone'];

// delete
queryUtils.delete = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (!_.isUndefined(req.query.deleted) && !_.isNull(req.query.deleted)) {
        if (req.query.deleted == '1') {
            // query deleted data
            query.where({isDelete: true});
        } else if (req.query.deleted == '0') {
            // not delete
            query.where({isDelete: false}); // default not delete
            // query.or([{isDelete: false}, {isDelete: {$exists: false}}]); // default not delete
        } else if (req.query.deleted == 'all') {
            // all data
        } else {
            // not delete
            query.where({isDelete: false}); // default not delete
            // query.or([{isDelete: false}, {isDelete: {$exists: false}}]); // default not delete
        }
    } else {
        query.where({isDelete: false}); // default not delete
        // query.or([{isDelete: false}, {isDelete: {$exists: false}}]); // default not delete
    }

    return query;
};

// kind
queryUtils.kind = function (req, query) {
    if (!req || !query) {
        return query;
    }
    // kind
    if (!_.isUndefined(req.query.kind) && !_.isNull(req.query.kind)) {
        let kind = parseInt(req.query.kind);
        if (!isNaN(kind)) {
            query.where('kind.index', kind);
        }
    }
    return query;
};


// delete
queryUtils.deleteAttribute = function (req, query, attribute) {
    if (!req || !query) {
        return query;
    }

    attribute = attribute || 'isDelete';

    if (!_.isUndefined(req.query.deleted) && !_.isNull(req.query.deleted)) {
        if (req.query.deleted == '1') {
            // query deleted data
            query.where({[attribute]: true});
        } else if (req.query.deleted == '0') {
            // not delete
            // query.where({isDelete: false}); // default not delete
            query.where({$or: [{[attribute]: false}, {[attribute]: {$exists: false}}]}); // default not delete
        } else if (req.query.deleted == 'all') {
            // all data
        } else {
            // not delete
            // query.where({isDelete: false}); // default not delete
            query.where({$or: [{[attribute]: false}, {[attribute]: {$exists: false}}]}); // default not delete
        }
    } else {
        // query.where({isDelete: false}); // default not delete
        query.where({$or: [{[attribute]: false}, {[attribute]: {$exists: false}}]}); // default not delete
    }

    return query;
};
// cellphone attribute
queryUtils.cellphoneAttribute = function (req, query, ...attribute) {
    if (!req || !query) {
        return query;
    }
    let conditions = [];
    if (attribute.length === 0) {
        conditions.push({cellphone: {$regex: req.query.cellphone}});
    } else {
        if (!_.isUndefined(req.query.cellphone) && !_.isNull(req.query.cellphone) && req.query.cellphone.length !== 0) {
            for (let i = 0; i < attribute.length; i++) {
                conditions.push({[attribute[i]]: {$regex: req.query.cellphone}});
            }
        }
    }
    if (conditions.length !== 0) {
        query.where({$or: conditions});
    }

    return query;
};
// realize
queryUtils.realize = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (!_.isUndefined(req.query.realized) && !_.isNull(req.query.realized)) {
        if (req.query.realized == '1') {
            // query deleted data
            query.where({isRealized: true});
        } else if (req.query.realized == '0') {
            // not delete
            query.where({isRealized: false}); // default not realized
        } else if (req.query.realized == 'all') {
            // all data
        } else {
            // not delete
            query.where({isRealized: false}); // default not realized
        }
    } else {
        query.where({isRealized: false}); // default not realized
    }

    return query;
};
// prize
queryUtils.prize = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.prize) && !_.isNull(req.query.prize)) {
        if (req.query.prize == '1') {
            // query deleted data
            query.where({isPrize: true});
        } else if (req.query.prize == '0') {
            // not delete
            query.where({isPrize: false}); // default not delete
        } else if (req.query.prize == 'all') {
            // all data
        } else {
            // not delete
            query.where({isPrize: false}); // default not delete
        }
    } else {
        query.where({isPrize: false}); // default not delete
    }

    return query;
};

// sort by comment count
queryUtils.sortByCommentCount = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.commentSort) && !_.isNull(req.query.commentSort)) {
        if (req.query.commentSort == '1') {
            // asc
            query.sort('commentCount');
        } else if (req.query.commentSort == '0') {
            // desc
            query.sort('-commentCount');
        } else if (req.query.commentSort == 'no') {
            // not sort by comment count
        } else {
            // desc
            query.sort('-commentCount');
        }
    } else {
        // desc default
        query.sort('-commentCount');
    }

    return query;
};

// sort by comment count
queryUtils.sortByPraiseCount = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.praiseSort) && !_.isNull(req.query.praiseSort)) {
        if (req.query.praiseSort == '1') {
            // asc
            query.sort('praiseCount');
        } else if (req.query.praiseSort == '0') {
            // desc
            query.sort('-praiseCount');
        } else if (req.query.praiseSort == 'no') {
            // not sort by comment count
        } else {
            // desc
            query.sort('-praiseCount');
        }
    } else {
        // desc default
        query.sort('-praiseCount');
    }

    return query;
};

// sort by comment count
queryUtils.date = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.date) && !_.isNull(req.query.date) && req.query.date.length !== 0) {
        // query.where({createTime: new Date(req.query.date)});
        let startTime = new Date(req.query.date);
        startTime.setHours(0);
        startTime.setMinutes(0);
        startTime.setSeconds(0);
        startTime.setMilliseconds(0);
        let endTime = new Date(startTime.getTime() + 1000 * 60 * 60 * 24);
        query.where('createTime').gte(startTime)
            .where('createTime').lte(endTime);
    }

    return query;
};

// start and end time
queryUtils.startEndTime = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (_.isUndefined(req.query.startTime) || _.isNull(req.query.startTime)) {
        return query;
    }

    if (_.isUndefined(req.query.endTime) || _.isNull(req.query.endTime)) {
        return query;
    }

    let startTime = new Date(req.query.startTime);
    startTime.setHours(0);
    startTime.setMinutes(0);
    startTime.setSeconds(0);
    startTime.setMilliseconds(0);

    let endTime = new Date(req.query.endTime);
    endTime.setHours(23);
    endTime.setMinutes(59);
    endTime.setSeconds(59);
    endTime.setMilliseconds(0);

    query.where('createTime').gte(startTime);
    query.where('createTime').lte(endTime);

    return query;
};

// author
queryUtils.author = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.author) && !_.isNull(req.query.author) && req.query.author.length !== 0) {
        query.where({author: {$regex: req.query.author}});
    }

    return query;
};

// creator with SessionUser
queryUtils.creatorWithSessionUser = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.session) && !_.isNull(req.session)) {
        if (!_.isUndefined(req.session.user) && !_.isNull(req.session.user) && !_.isUndefined(req.session.user._id)) {
            query.where({creator: req.session.user});
        }
    }

    return query;
};

// cellphone
queryUtils.cellphone = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.cellphone) && !_.isNull(req.query.cellphone) && req.query.cellphone.length !== 0) {
        query.where({cellphone: {$regex: req.query.cellphone}});
    }

    return query;
};

// content
queryUtils.content = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.content) && !_.isNull(req.query.content) && req.query.content.length !== 0) {
        query.where({content: {$regex: req.query.content}});
    }

    return query;
};

// content
queryUtils.no = function (req, query) {
    if (!req || !query) {
        return;
    }
    if (!_.isUndefined(req.query.no) && !_.isNull(req.query.no) && req.query.no.length !== 0) {
        query.$where(format('this.no.toString().match(/{}/)', req.query.no));
    }

    return query;
};

// fuzzy query
queryUtils.fuzzy = function (req, query, fields) {
    if (!req || !query) {
        return query;
    }
    if (Object.prototype.toString.call(fields) !== '[object Array]') {
        return query;
    }
    if (fields.length == 0) {
        return query;
    }
    if (!_.isUndefined(req.query.fuzzy) && !_.isNull(req.query.fuzzy) && req.query.fuzzy.length !== 0) {
        let queryArray = [];

        for (let i = 0; i < fields.length; i++) {
            let item = {
                $where: format('this.{}.toString().match(/{}/)', fields[i], req.query.fuzzy)
            };

            queryArray.push(item);
        }

        query.or(queryArray);
    }

    return query;
};

// company
queryUtils.company = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.company) && !_.isNull(req.query.company) && req.query.company.length !== 0) {
        query.where({company: {$regex: req.query.company}});
    }

    return query;
};

// pass
queryUtils.pass = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (!_.isUndefined(req.query.pass) && !_.isNull(req.query.pass)) {
        if (req.query.pass == '1') {
            // query pass data
            query.where({isPassed: true});
        } else if (req.query.pass == '0') {
            // not pass
            query.where({isPassed: false}); // default not pass
        } else if (req.query.pass == 'all') {
            // all data
        } else {
            // not delete
            query.where({isPassed: true}); // default not pass
        }
    } else {
        query.where({isPassed: true}); // default not pass
    }

    return query;
};

// location
queryUtils.location = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (_.isUndefined(req.query.location) || _.isNull(req.query.location) || Object.keys(req.query.location).length == 0) {
        return;
    }
    if (_.isString(req.query.location)) {
        req.query.location = JSON.parse(req.query.location);
    }

    // province
    if (!_.isUndefined(req.query.location.province) && !_.isNull(req.query.location.province) && req.query.location.province.length !== 0) {
        query.where({'location.province': req.query.location.province});
    }
    // city
    if (!_.isUndefined(req.query.location.city) && !_.isNull(req.query.location.city) && req.query.location.city.length !== 0) {
        query.where({'location.city': req.query.location.city});
    }
    // district
    if (!_.isUndefined(req.query.location.district) && !_.isNull(req.query.location.district) && req.query.location.district.length !== 0) {
        query.where({'location.district': req.query.location.district});
    }
    // detail
    if (!_.isUndefined(req.query.location.detail) && !_.isNull(req.query.location.detail) && req.query.location.detail.length !== 0) {
        query.where({'location.detail': {$regex: req.query.location.detail}});
    }

    return query;
};

// email
queryUtils.email = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.email) && !_.isNull(req.query.email) && req.query.email.length !== 0) {
        query.where({email: {$regex: req.query.email}});
    }

    return query;
};

// name
queryUtils.name = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.name) && !_.isNull(req.query.name) && req.query.name.length !== 0) {
        query.where({name: {$regex: req.query.name}});
    }

    return query;
};

// name
queryUtils.nameOrNickname = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.name) && !_.isNull(req.query.name) && req.query.name.length !== 0) {
        query.where({$or: [{name: {$regex: req.query.name}}, {nickname: {$regex: req.query.name}}]});
    }

    return query;
};

// title
queryUtils.title = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.title) && !_.isNull(req.query.title) && req.query.title.length !== 0) {
        // query.where({title: {$regex: req.query.title}});
        query.where({title: '/^' + req.query.title + '/'});
    }

    return query;
};

// text
queryUtils.text = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.text) && !_.isNull(req.query.text) && req.query.text.length !== 0) {
        // query.where({title: {$regex: req.query.title}});
        query.where({$text: {$search: req.query.text}});
    }

    return query;
};

// isbn10
queryUtils.isbn10 = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.isbn10) && !_.isNull(req.query.isbn10) && req.query.isbn10.length !== 0) {
        query.where({isbn10: req.query.isbn10});
    }

    return query;
};

// isbn13
queryUtils.isbn13 = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.isbn13) && !_.isNull(req.query.isbn13) && req.query.isbn13.length !== 0) {
        query.where({isbn13: req.query.isbn13});
    }

    return query;
};


// name attribute
queryUtils.nameAttribute = function (req, query, ...attribute) {
    if (!req || !query) {
        return query;
    }

    let conditions = [];
    if (attribute.length === 0) {
        conditions.push({name: {$regex: req.query.name}});
    } else {
        if (!_.isUndefined(req.query.name) && !_.isNull(req.query.name) && req.query.name.length !== 0) {
            for (let i = 0; i < attribute.length; i++) {
                conditions.push({[attribute[i]]: {$regex: req.query.name}});
            }
        }
    }
    if (conditions.length !== 0) {
        query.where({$or: conditions});
    }

    return query;
};

// name
queryUtils.nameAggregate = function (req, aggregate) {
    if (!req || !aggregate) {
        return aggregate;
    }
    if (!_.isUndefined(req.query.name) && !_.isNull(req.query.name) && req.query.name.length !== 0) {
        aggregate.match({'name': {$regex: req.query.name}});
    }

    return aggregate;
};
// start and end time
queryUtils.startEndTimeAggregate = function (req, aggregate) {
    if (!req || !aggregate) {
        return aggregate;
    }

    if (_.isUndefined(req.query.startTime) || _.isNull(req.query.startTime)) {
        return aggregate;
    }

    if (_.isUndefined(req.query.endTime) || _.isNull(req.query.endTime)) {
        return aggregate;
    }

    let startTime = new Date(req.query.startTime);
    startTime.setHours(0);
    startTime.setMinutes(0);
    startTime.setSeconds(0);
    startTime.setMilliseconds(0);

    let endTime = new Date(req.query.endTime);
    endTime.setHours(23);
    endTime.setMinutes(59);
    endTime.setSeconds(59);
    endTime.setMilliseconds(0);

    aggregate.match({'createTime': {$gte: startTime}});
    aggregate.match({'createTime': {$lte: endTime}});

    return aggregate;
};

// delete
queryUtils.deleteAggregate = function (req, aggregate) {
    if (!req || !aggregate) {
        return aggregate;
    }

    if (!_.isUndefined(req.query.deleted) && !_.isNull(req.query.deleted)) {
        if (req.query.deleted == '1') {
            // query deleted data
            aggregate.match({isDelete: true});
        } else if (req.query.deleted == '0') {
            // not delete
            aggregate.match({isDelete: false}); // default not delete
        } else if (req.query.deleted == 'all') {
            // all data
        } else {
            // not delete
            aggregate.match({isDelete: false}); // default not delete
        }
    } else {
        aggregate.match({isDelete: false}); // default not delete
    }

    return aggregate;
};
// field attribute
queryUtils.fieldAttribute = function (req, query, queryField, ...attribute) {
    if (!req || !query || !queryField || attribute.length === 0) {
        return query;
    }

    let conditions = [];
    if (!_.isUndefined(req.query[queryField]) && !_.isNull(req.query[queryField]) && req.query[queryField].length !== 0) {
        for (let i = 0; i < attribute.length; i++) {
            conditions.push({[attribute[i]]: {$regex: req.query[queryField]}});
        }
    }

    if (conditions.length !== 0) {
        query.where({$or: conditions});
    }

    return query;
};

// ticketCheckStatus
queryUtils.ticketCheckStatus = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (!_.isUndefined(req.query.checkStatus) && !_.isNull(req.query.checkStatus)) {
        if (req.query.checkStatus == '0' || req.query.checkStatus == '1' || req.query.checkStatus == '2') {
            // untreated, passed, reject
            query.where({'tickets.checkStatus': parseInt(req.query.checkStatus)});
        } else {
            // all data
        }
    } else {
        // all data
    }

    return query;
};
// ticketCheckStatus
queryUtils.checkStatus = function (req, query) {
    if (!req || !query) {
        return query;
    }

    if (!_.isUndefined(req.query.checkStatus) && !_.isNull(req.query.checkStatus)) {
        let status = parseInt(req.query.checkStatus);
        if (_.isNaN(status)) {
            if (req.query.checkStatus === 'all') {
                // all
            } else {
                // pass
                query.where({checkStatus: CheckStatus.passed});
            }
        } else {
            query.where({checkStatus: req.query.checkStatus});
        }
    } else {
        // pass
        query.where({checkStatus: CheckStatus.passed});
    }

    return query;
};
// creator
queryUtils.creator = function (req, query) {
    if (!req || !query) {
        return query;
    }
    if (!_.isUndefined(req.query.creator) &&
        !_.isNull(req.query.creator) &&
        req.query.creator.length !== 0 &&
        ObjectId.isValid(req.query.creator)) {

        query.where({creator: req.query.creator});
    }

    return query;
};
